#include <stdio.h>
#include <argp.h>
#include "y.tab.c"
#include "lex.yy.c"
#include "schema.h"
#include "minizincmodel.h"


//options -m and -M
extern char* minInt; //minimum value for int variables in the test-case
extern char* maxInt; // maximum value for int variables in the test-case


const char *argp_program_version =
"stcg 0.1";

const char *argp_program_bug_address =
"<senrof21@gmail.com> or <jose.11.10.88@gmail.com>";

/* This structure is used by main to communicate with parse_opt. */
struct arguments
{
  int verbose;             /* The -v flag */
  char *outfile, *infile;  /* Arguments for -o and -i */
  char *schema, *formula;  /* Arguments for -s and -f */
};

/*
   OPTIONS.  Field 1 in ARGP.
   Order of fields: {NAME, KEY, ARG, FLAGS, DOC}.
*/
static struct argp_option options[] =
{
  {"verbose", 'v', 0, 0, "Produce verbose output"},
  {"schema",   's', "SCHEMA_NAME", 0,
   "Shows the generated schema for SCHEMA_NAME view or table"},
  {"formula",   'f', "SCHEMA_NAME", 0,
   "Shows the generated formula for SCHEMA_NAME view or table"},
  {"output",  'o', "OUTFILE", 0,
   "Output to OUTFILE instead of to standard output"},
  {"input",  'i', "INFILE", 0,
   "Input from INFILE instead of from standard input"},
  {"minInt",  'm', "MIN_INT_VALUE", 0,
   "Sets the minimum value for int variables in the database test-case"},
  {"maxInt",  'M', "MAX_INT_VALUE", 0,
   "Sets the maximum value for int variables in the database test-case"},
  {0}
};


/*
   PARSER. Field 2 in ARGP.
   Order of parameters: KEY, ARG, STATE.
*/
static error_t
parse_opt (int key, char *arg, struct argp_state *state)
{
  struct arguments *arguments = (struct arguments *) state->input;

  switch (key)
    {
    case 'v':
      arguments->verbose = 1;
      break;
    case 's':
      arguments->schema = arg;
      break;
    case 'f':
      arguments->formula = arg;
      break;
    case 'o':
      arguments->outfile = arg;
      break;
    case 'i':
      arguments->infile = arg;
      break;
    case 'm':
      minInt = arg;
      break;
    case 'M':
       maxInt = arg;     
      break;
 /*  case ARGP_KEY_ARG:
      if (state->arg_num >= 2)
	{
	  argp_usage(state);
	}
      arguments->args[state->arg_num] = arg;
      break;*/
    case ARGP_KEY_END:
      if (state->arg_num != 0)
	{
	  argp_usage (state);
	}
	break;
    default:
      return ARGP_ERR_UNKNOWN;
    }
  return 0;
}

/*
   ARGS_DOC. Field 3 in ARGP.
   A description of the non-option command-line arguments
     that we accept.
*/
static char args_doc[] = ""; //"ARG1 ARG2";

/*
  DOC.  Field 4 in ARGP.
  Program documentation.
*/
static char doc[] =
"stcg -- A program to generate positive test case for SQL schemas.\vBy Antonio Tenorio Fornés & José Luzón Martín.";

/*
   The ARGP structure itself.
*/
static struct argp argp = {options, parse_opt, args_doc, doc};


int main (int argc, char **argv)
{
  struct arguments arguments;
  FILE *outstream;
  FILE *instream;

  /* Set argument defaults */
  arguments.outfile = NULL;
  arguments.infile = NULL;
  arguments.formula = "";
  arguments.schema = "";
  arguments.verbose = 0;

  /* Parse arguments */
  argp_parse (&argp, argc, argv, 0, 0, &arguments);

  /* Where do we send output? */

  if (arguments.infile)
    instream = fopen (arguments.infile, "r");
  else instream = stdin;
  stdin=instream;

  if (arguments.outfile)
    outstream = fopen (arguments.outfile, "w");
  else
    outstream = stdout;

 Schema* sch = new Schema();
 sch = generateSchema();
 FormulaGenerator * generator=NULL;
 if (sch!=NULL) generator = new FormulaGenerator(sch);
  if(strcmp(arguments.formula,"")==0){

   arguments.formula=new char[256];
    std::cout << "Please, write the name of the table or view you want to generate it's formula:\n";
    std::cin.getline(arguments.formula,256);
  }

 SchemaComponentFormula * formula = NULL;
    if(generator!=NULL && generator->generateFormulaFor(arguments.formula,formula)){
      fprintf(outstream,"\n % ||  %s \n", formula->toString().c_str());
      MiniZincModel * minizinc_model = new MiniZincModel(formula);   
      fprintf(outstream,"\n %s \n", (char*) minizinc_model->toString().c_str());
	  delete minizinc_model; minizinc_model = NULL;
    }
    //TODO implement printing of specific schema if -s param is specified
    if (arguments.verbose) std::cout<<sch->toString();
	
	delete sch; sch = NULL;
    delete generator; generator = NULL;
  return 0;
}
